package com.sunyard.utils.sm2;

import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECPoint;

import java.math.BigInteger;

public final class SM2PublicKey implements ECPublicKey {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private final ECParameterSpec sm2ParameterSpec = SM2Params.sm2ParameterSpec;
    private byte[] bPubX = null;
    private byte[] bPubY = null;
    private BigInteger iPubX = null;
    private BigInteger iPubY = null;
    private final ECPoint Q;
    private final byte[] zvalue;

    public SM2PublicKey(byte[] bPubX, byte[] bPubY) {
        if (bPubX == null) {
            throw new IllegalArgumentException("null not allowed for bPubX");
        }
        if (bPubY == null) {
            throw new IllegalArgumentException("null not allowed for bPubY");
        }

        iPubX = new BigInteger(1, bPubX);
        iPubY = new BigInteger(1, bPubY);
        this.Q = createPoint(null, new BigInteger(1, bPubX), new BigInteger(1,
                bPubY));
        this.zvalue = SM2Params.calcZ(bPubX, bPubY);
    }

    private final ECPoint createPoint(ECPoint point, BigInteger iPubX,
                                      BigInteger iPubY) {

        ECPoint Q = null;
        Q = this.sm2ParameterSpec.getCurve().createPoint(iPubX, iPubY);
        bPubX = asUnsignedNByteArray(iPubX, 32);
        bPubY = asUnsignedNByteArray(iPubY, 32);
        return Q;
    }

    public static byte[] asUnsignedNByteArray(BigInteger x, int length) {
        if (x == null)
            return null;
        byte[] tmp = new byte[length];
        byte[] arrays = x.toByteArray();
        int len = arrays.length;
        if (len > length + 1)
            return null;
        if (len == length + 1) {
            if (arrays[0] != 0) {
                return null;
            }
            System.arraycopy(arrays, 1, tmp, 0, length);
            return tmp;
        }

        System.arraycopy(arrays, 0, tmp, length - len, len);
        return tmp;
    }

    public byte[] getPubXByBytes() {
        return (byte[]) (byte[]) this.bPubX.clone();
    }

    public byte[] getPubYByBytes() {
        return (byte[]) (byte[]) this.bPubY.clone();
    }


    public ECParameterSpec getParameters() {
        // TODO Auto-generated method stub
        return this.sm2ParameterSpec;
    }


    public String getAlgorithm() {
        // TODO Auto-generated method stub
        return "SM2";
    }


    public byte[] getEncoded() {
        // TODO Auto-generated method stub
        return null;
    }


    public String getFormat() {
        // TODO Auto-generated method stub
        return null;
    }


    public ECPoint getQ() {
        return this.Q;
    }

    public final byte[] getDefaultZ() {
        return (byte[]) (byte[]) this.zvalue.clone();
    }

    public BigInteger getPubX_Int() {
        return this.iPubX;
    }

    public BigInteger getPubY_Int() {
        return this.iPubY;
    }

    public final byte[] calcZ(byte[] userId) {
        return SM2Params.calcZ(this.bPubX, this.bPubY, userId);
    }

    public String getHexPubKey() {
        return this.iPubX.toString(16) + this.iPubY.toString(16);
    }

}
